import { Context, Next } from 'koa';
import jwt from 'jsonwebtoken';
import { config } from '../config';
import { redisClient } from '../database';
import { AppError } from './errorHandler';

/**
 * 认证中间件
 * 验证请求头中的JWT令牌
 */
export const authMiddleware = async (ctx: Context, next: Next) => {
  // 获取请求头中的Authorization
  const authHeader = ctx.headers.authorization;

  // 检查Authorization是否存在
  if (!authHeader) {
    throw new AppError('未提供认证令牌', 401);
  }

  // 检查Authorization格式
  const parts = authHeader.split(' ');
  if (parts.length !== 2 || parts[0] !== 'Bearer') {
    throw new AppError('认证令牌格式错误', 401);
  }

  const token = parts[1];

  try {
    // 验证Token
    const decoded: any = jwt.verify(token, config.jwt.secret);

    // 从Redis获取保存的Token
    const savedToken = await redisClient.get(`token:${decoded.id}`);

    // 验证Token是否存在于Redis
    if (!savedToken || savedToken !== token) {
      throw new AppError('无效的认证令牌', 401);
    }

    // 将解码后的用户信息保存到ctx.state
    ctx.state.user = decoded;

    // 继续处理请求
    await next();
  } catch (error) {
    if (error.name === 'TokenExpiredError') {
      throw new AppError('认证令牌已过期', 401);
    }
    throw new AppError('无效的认证令牌', 401);
  }
};

/**
 * 角色验证中间件
 * 验证用户是否具有指定角色
 * @param roles 允许的角色数组
 */
export const roleMiddleware = (roles: string[]) => {
  return async (ctx: Context, next: Next) => {
    // 确保用户已通过认证
    if (!ctx.state.user) {
      throw new AppError('未认证', 401);
    }

    // 获取用户角色
    const userRole = ctx.state.user.role;

    // 检查用户角色是否在允许的角色列表中
    if (!roles.includes(userRole)) {
      throw new AppError('没有权限执行此操作', 403);
    }

    // 继续处理请求
    await next();
  };
}; 